<?php
namespace app\websocket;

use Workerman\Connection\TcpConnection;
use Workerman\Connection\AsyncTcpConnection;

use Webman\Openai\Chat;
use Workerman\Protocols\Http\Chunk;
use Workerman\Protocols\Http\Request;
use Workerman\Protocols\Http\Response;
use Workerman\Protocols\Websocket;

use Workerman\Worker;
use Workerman\Timer;


use support\Log;
use think\facade\Db;
use support\Redis;


class SttHandler
{
    private $redis_config;
    private $check_time_out = 3;

    public function onWorkerStart (Worker $worker)
    {
      $this->redis_config = Redis::connection("config");
    }


    public function onWebSocketConnect(TcpConnection $connection, $http_buffer)
    {
      $connection->Authentication = false;
      //创建定时器，如果连接超过10秒未认证，则关闭连接
      Timer::add($this->check_time_out, function() use ($connection){
        if($connection->Authentication == false)
        {
          $connection->send(json_encode(['status'=>400,'message'=>'Authentication failed']));
          $connection->close();
        }
      }, [], false);
    }


    public function onMessage(TcpConnection $connection, $data)
    {
      Log::info("onMessage:".$data. "\n");
    

      if(!isjson($data))
      {
        if($connection->Authentication == false)
        {
          $connection->send(json_encode(['status'=>400,'message'=>'authentication failed']));
          return;
        }
        // Log::info(' 接收到的前端二进制信息：'.$data);
        $connection->con->websocketType = Websocket::BINARY_TYPE_ARRAYBUFFER;
        $connection->con->send($data);
      }else{
        $dataJson = json_decode($data,true);
        if($dataJson == null)
        {
          $connection->send(json_encode(['status'=>400,'message'=>'data format error']));
          return;
        }
        // 根据类型不同，执行不同操作接口
        if(isset($dataJson['meta_type']))
        {
           // 验证信息
          $meta_id = $dataJson['meta_id'];
          $meta_type = $dataJson['meta_type'];
          $stt_type = $dataJson['stt_type'];
           //判断参数是否存在
          if(!isset($meta_id) || !isset($meta_type) || !isset($stt_type))
          {
            $connection->send(json_encode(['status'=>400,'message'=>'meta type not found']));
            return;
          }
          $this->checkUser($connection,$meta_id,$meta_type,$stt_type);

          switch($connection->type)
          {
            case "aly":
              $this->bindConAly($connection);
              break;
            case "paddspeech":
              $connection->send(json_encode(['status'=>400,'message'=>'paddspeech 完善中 ']));
              $connection->close();
              break;
            default:
              $connection->send(json_encode(['status'=>400,'message'=>'tts type not found']));
              $connection->close();
              break;
          }

        }
        elseif($connection->con  && $connection->type)
        {
          if($connection->Authentication == false)
          {
            $connection->send(json_encode(['status'=>400,'message'=>'authentication failed']));
            return;
          }
          $connection->con->websocketType = Websocket::BINARY_TYPE_BLOB;
          switch($connection->type)
          {
            case "aly":
              $this->bindMeesageAly($data,$connection);
              break;
            case "paddspeech":
              $connection->send(json_encode(['status'=>400,'message'=>'paddspeech 完善中 ']));
              $connection->close();
              break;
            default:
              $connection->send(json_encode(['status'=>400,'message'=>'stt type not found']));
              $connection->close();
              break;
          }
        }
      }
    }


    public function onClose(TcpConnection $connection)
    {
      $connection->destroy();
      if(isset($connection->con))
      {
        $connection->con->close();
        $connection->con->destroy();
      }
    }

    //验证用户身份
    private function checkUser(TcpConnection &$connection,$meta_id,$meta_type,$stt_type)
    {
      switch ($meta_type) {
        case 'web':
          $res = Db::name("meta_web")
                    ->field('meta_id, role_id')
                    ->where('meta_id', $meta_id)
                    ->find();
          if($res == null)
          {
            $connection->send(json_encode(['status'=>400,'message'=>'meta not found']));
            $connection->close();
          }

          $config = getConfigByType('stt', $stt_type);
          if($config === false)
          {
            $connection->send(json_encode(['status'=>400,'message'=>'ttstype not found']));
            $connection->close();
          }

          $connection->type = $stt_type;
          $connection->appkey = $config['appkey'];
          $connection->url = $config['url'];
          break;
        case "ue":
          $res = Db::name("ue")
                    ->field('meta_id, role_id')
                    ->where('meta_id', $meta_id)
                    ->find();
          if($res == null)
          {
            $connection->send(json_encode(['status'=>400,'message'=>'meta not found']));
            $connection->close();
          }  
          
          $config = getConfigByType('stt', $stt_type);
          if($config === false)
          {
            $connection->send(json_encode(['status'=>400,'message'=>'ttstype not found']));
            $connection->close();
          }


          $connection->type = $stt_type;
          $connection->appkey = $config['appkey'];
          $connection->url = $config['url'];
          break;
        default:
          $connection->send(json_encode(['status'=>400,'message'=>'meta type not found']));
          $connection->close();
          break;
      }

      $connection->Authentication = true;
    }

    private function bindMeesageAly($data, TcpConnection $connection)
    {
      $dataJson = json_decode($data, true);
      $actionName = $dataJson["name"];
      $message_id = generateHex(32);
      switch($actionName)
      {
          case "start":
            $format = $dataJson["format"];
            $sample_rate = $dataJson["sample_rate"];
            $task_id = generateHex(32);
            $connection->task_id = $task_id;
            $sendData = [
                "header" =>
                [
                    "message_id" => $message_id,
                    "task_id" => $task_id,
                    "namespace"=> "SpeechTranscriber",
                    "name" => "StartTranscription",
                    "appkey" => $connection->appkey,
                ],
                "payload" =>
                [
                    "format" => $format,
                    "sample_rate" => $sample_rate,
                    "enable_intermediate_result" => true,
                    "enable_punctuation_prediction" => true,
                    "enable_inverse_text_normalization" => true
                ]
            ];
            $connection->con->send(json_encode($sendData));
          break;
          case "stop":
            $sendData =  [
                "header" =>  [
                    "message_id" => $message_id,
                    "task_id" => $connection->task_id,
                    "namespace"=> "SpeechTranscriber",
                    "name"=> "StopTranscription",
                    "appkey"=>  $connection->appkey
                ]
            ];
            $connection->con->send(json_encode($sendData));
          break;
      }
    }


    private function bindConAly(TcpConnection &$connection)
    {
      $token = getToken("aly");
      $url = $connection->url."?token=".$token;
      
      $con = new AsyncTcpConnection($url);
      $con->transport = 'ssl';
      $con->onWebSocketConnect = function(AsyncTcpConnection $con ) use ($connection)  {
          $sendData = [
              'status' => 200,
              "name" => 'connected'
          ];
          $connection->send(json_encode($sendData));
      };

      $con->onMessage = function(AsyncTcpConnection $con, $data) use ($connection)  {
          // Log::info(' 接收到的阿里云信息：'.$data);
          $dataJson = json_decode($data);
          if(isset($dataJson->header))
          {
              $actionName = $dataJson->header->name;
              $result = isset($dataJson->payload) && isset($dataJson->payload->result)  ? $dataJson->payload->result : "";
              $sendData = [];
              switch($actionName)
              {
                  case "TranscriptionStarted":
                      // 准备好了，可以开始识别了
                      $sendData = [
                          "status" => 200,
                          "name" => "started"
                      ];
                      break;
                  case "TranscriptionResultChanged":
                      $sendData = [
                          "status" => 200,
                          "name" => "resultChanged",
                          "content"=> $result
                      ];
                      Log::info('STT 语音识别变化:'.$result);

                      //    识别结果又变化
                      break;
                  case "SentenceEnd":
                      // 一句话结束
                      $sendData = [
                          "status" => 200,
                          "name" => "sentenceEnd",
                          "content"=> $result
                      ];
                      break;
                  case "TranscriptionCompleted";
                      // 转写结束
                      $sendData = [
                          "status" => 200,
                          "name" => "completed",
                          "content"=> $result
                      ];
                      break;
              }
              if($sendData)
              {
                  $connection->send(json_encode($sendData));
              }
          }
      };

      $connection->con = $con;
      $con->connect();
    }
}


?>